// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "CaeClientService.h"
#include "../cae_agent/CaeAgent.h"
#include "../cae_common/CaeLogConfig.h"
#include "../cae_socket/CaeWebSocket.h"
#include "../cae_socket/CaeTlsSocket.h"
#include "../cae_socket/CaeWssSocket.h"

void CaeServerNotice::Notice(void *socket)
{
    CaeAgent::GetInstance().Restart();
}

CaeTcpClientService::CaeTcpClientService()
{
    m_clientCount = 0;
    m_notice = nullptr;
}

CaeTcpClientService::~CaeTcpClientService()
{
    LOGI("Destructor CaeTcpTlsClientService.");
    if (m_notice != nullptr) {
        delete m_notice;
        m_notice = nullptr;
    }
}

void CaeTcpClientService::Callback(void *socket)
{
    LOGI("An %s client coming.", ClientType2string(ClientType::APP_TCP).c_str());
    CaeSocketAgent::GetInstance().SetClientSocket((CaeSocket *)socket);
}

CaeTcpTlsClientService::CaeTcpTlsClientService()
{
    m_notice = nullptr;
}

CaeTcpTlsClientService::~CaeTcpTlsClientService()
{
    if (m_notice != nullptr) {
        delete m_notice;
        m_notice = nullptr;
    }
}

void CaeTcpTlsClientService::Callback(void *socket)
{
    LOGI("An %s client coming.", ClientType2string(ClientType::APP_TLS).c_str());
    CaeSocketAgent::GetInstance().SetClientSocket((CaeSocket *)socket);
}

CaeWebClientService::CaeWebClientService()
{
    m_clientCount = 0;
    m_notice = nullptr;
}

CaeWebClientService::~CaeWebClientService()
{
    if (m_notice != nullptr) {
        delete m_notice;
        m_notice = nullptr;
    }
}

void CaeWebClientService::Callback(void *socket)
{
    LOGI("A %s client coming.", ClientType2string(ClientType::H5_WS).c_str());
    auto *tcpSocket = (CaeTcpSocket *)socket;
    CaeWebSocket *webSocket = new CaeWebSocket(tcpSocket);
    if (!webSocket->InitCaeWebSocket()) {
        LOGE("InitCaeWebSocket failed.");
        delete webSocket;
        CaeAgent::GetInstance().SetIsUserConnected(false);
        return;
    }
    webSocket->SetSocketOption(SOCKET_OPTION_BITSET_NODELAY | SOCKET_OPTION_BITSET_QUICKACK);
    CaeHandshakeTimeoutTimer *caeHandshakeTimeoutTimer =
        new CaeHandshakeTimeoutTimer(webSocket, CaeConfigManage::GetOutTimes() * CaeConfigManage::GetBaseTime());
    caeHandshakeTimeoutTimer->Start();
    CaeTimerManage::GetInstance().AddTimer(caeHandshakeTimeoutTimer);
    if (!webSocket->Handshake()) {
        LOGE("Web socket handshake failed, close this socket.");
        delete webSocket;
        CaeAgent::GetInstance().SetIsUserConnected(false);
        CaeTimerManage::GetInstance().DeleteTimer(caeHandshakeTimeoutTimer);
        return;
    }
    LOGI("Web socket handshake successfully.");

    caeHandshakeTimeoutTimer->Stop();
    CaeTimerManage::GetInstance().DeleteTimer(caeHandshakeTimeoutTimer);
    CaeSocketAgent::GetInstance().SetClientSocket(webSocket);
}

CaeWSSClientService::CaeWSSClientService()
{
    m_clientCount = 0;
    m_notice = nullptr;
}

CaeWSSClientService::~CaeWSSClientService()
{
    if (m_notice != nullptr) {
        delete m_notice;
        m_notice = nullptr;
    }
}

void CaeWSSClientService::Callback(void *socket)
{
    LOGI("A %s client coming.", ClientType2string(ClientType::H5_WSS).c_str());
    auto *tlsSocket = (CaeTlsSocket *)socket;
    auto *wssSocket = new CaeWssSocket(tlsSocket);
    if (!wssSocket->InitCaeWebSocket()) {
        LOGE("InitCaeWebSocket failed.");
        delete wssSocket;
        CaeAgent::GetInstance().SetIsUserConnected(false);
        return;
    }
    wssSocket->SetSocketOption(SOCKET_OPTION_BITSET_NODELAY | SOCKET_OPTION_BITSET_QUICKACK);
    auto *caeHandshakeTimeoutTimer =
        new CaeHandshakeTimeoutTimer(wssSocket, CaeConfigManage::GetOutTimes() * CaeConfigManage::GetBaseTime());
    caeHandshakeTimeoutTimer->Start();
    CaeTimerManage::GetInstance().AddTimer(caeHandshakeTimeoutTimer);
    if (!wssSocket->Handshake()) {
        LOGE("Web socket wss handshake failed, close this socket.");
        delete wssSocket;
        CaeAgent::GetInstance().SetIsUserConnected(false);
        caeHandshakeTimeoutTimer->Stop();
        CaeTimerManage::GetInstance().DeleteTimer(caeHandshakeTimeoutTimer);
        return;
    }
    LOGI("Web socket wss handshake successfully.");

    caeHandshakeTimeoutTimer->Stop();
    CaeTimerManage::GetInstance().DeleteTimer(caeHandshakeTimeoutTimer);
    CaeSocketAgent::GetInstance().SetClientSocket(wssSocket);
}